package ru.urfc.portal.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import ru.urfc.portal.dao.BasePersistence;
import ru.urfc.portal.dao.Paging;
import ru.urfc.portal.dao.SpectrId;
import ru.urfc.portal.dao.filter.Filter;
import ru.urfc.portal.dao.filter.VariablesHolder;
import ru.urfc.portal.model.Branch;
import ru.urfc.portal.model.SysObject;

@Stateless
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class BasePersistenceImpl extends BaseDao implements BasePersistence {
	
	@Override
	public <T> T persist(T entity) {
		EntityManager entityManager = choseEntityManager(Branch.SVERD, entity.getClass());
		entityManager.persist(entity);
		return entity;
	}
	
	@Override
	public <T> T findById(Class<T> klass, Long id) {
		return exactlyOne(find(klass, "id", id));
	}

	@Override
	public <T> T findById(Class<T> klass, SpectrId spectrId) {
		return exactlyOne(find(spectrId.getBranch(), klass, "id", spectrId.getId()));
	}
	
	@Override
	public <T> List<T> find(Class<T> klass, String fieldName, Object value) {
		return find(null, klass, fieldName, value);
	}
	
	@Override
	public <T> List<T> find(Branch branch, Class<T> klass, String fieldName, Object value) {
		return find(branch, klass, new Filter(fieldName, value));
	}
	
	@Override
	public <T> List<T> find(Class<T> klass, Filter filter) {
		return find(null, klass, filter);
	}	

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> find(Branch branch, Class<T> klass, Filter filter) {
		if (filter.getPaging().isMaxResultsZeroOrNegative()) {
			return (List<T>) new ArrayList<Object>();
		}
		EntityManager entityManager = choseEntityManager(branch, klass);
		VariablesHolder variablesHolder = new VariablesHolder();
		Query query = entityManager.createQuery(format(
				"SELECT this FROM {0} this {1} {2} {3}",
				klass.getSimpleName(), filter.getFetches(), 
				filter.isNeedWhere()? "WHERE": "", filter.generate(variablesHolder)));
		for (String name: variablesHolder.getKeySet()) {
			query.setParameter(name, variablesHolder.get(name));
		}
		filter.getPaging().enchnceQuery(query);
		return query.getResultList();
	}

	/**
	 * For DAOs only
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findWhere(Branch branch, Class<T> klass, String expression, String orderBy, Paging paging, Object ... parameters) {
		EntityManager entityManager = choseEntityManager(branch, klass);
		orderBy = orderBy == null || orderBy.trim().equals("")? "": " ORDER BY " + orderBy;
		Query query = entityManager.createQuery(format(
				"SELECT this FROM {0} this WHERE {1}" + orderBy,
				klass.getSimpleName(), expression));
		for (int i = 0; i < parameters.length; ++i) {
			query.setParameter(i + 1, parameters[i]);
		}
		paging.enchnceQuery(query);
		return query.getResultList();
	}
	
	@Override
	public <T> void delete(Class<T> klass, String fieldName, Object value) {
		Query query = getSysEntityManager().createQuery(format(
				"DELETE FROM {0} WHERE {1} = :value", klass.getSimpleName(), fieldName));
		query.setParameter("value", value);
		query.executeUpdate();
	}
	
	@Override
	public <T> void delete(Class<T> klass, Long id) {
		delete(klass, "id", id);
	}
	
	@Override
	public void delete(SysObject entity) {
		delete(entity.getClass(), "id", entity.getId());
	}
	
	@Override
	public void detach(SysObject ...entities) {
		EntityManager entityManager = getSysEntityManager();
		for (SysObject entity: entities) {
			entityManager.detach(entity);
		}
		entityManager.flush();
	}

	@Override
	public void flush() {
		getSysEntityManager().flush();
	}
}